package com.ruoyi.course.UtilMCTSCourseScheduling;

import com.ruoyi.classroom.domain.classroom;
import com.ruoyi.course.UtilMCTSCourseScheduling.DataPreprocessor.CourseClassInfo;
import com.ruoyi.course.UtilMCTSCourseScheduling.DataPreprocessor.SchedulingData;
import com.ruoyi.course.UtilMCTSCourseScheduling.DataPreprocessor.SchedulingConstraints;
import com.ruoyi.course.UtilMCTSCourseScheduling.DataPreprocessor.TimeSlot;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.stream.Collectors;

public class MctsState {

    // 日志工具
    private static final Logger logger = LoggerFactory.getLogger(MctsState.class);

    // 1.3.1 迭代终止条件参数
    private int maxIterations = 10000;
    private long timeoutMillis = 3 * 60 * 1000;
    private int earlyStopThreshold = 2000;
    private double scoreImprovementThreshold = 0.01;

    // 1.3.2 状态评估参数
    private double teacherConstraintWeight = 0.6;
    private double classroomUtilizationWeight = 0.4;
    private int baseScore = 60;
    private int maxTeacherScore = 20;
    private int maxClassroomScore = 20;

    // 核心属性定义
    private SchedulingData schedulingData;
    private SchedulingConstraints constraints;
    private DataAccessor dataAccessor;

    // 原始资源数据
    private Map<String, Set<TimeSlot>> originalStudentTimeSlotsMap;
    private Map<String, Set<TimeSlot>> originalTeacherOccupancy;
    private Map<String, Set<TimeSlot>> originalClassroomOccupancy;
    private Set<TimeSlot> allAvailableTimeSlots;

    // 排课进度数据 - 核心修改：支持连续课时和每周次数
    private Map<String, List<List<TimeSlot>>> scheduledSessions; // 课程班ID -> 连续课时组合列表
    private Map<String, Integer> scheduledCountPerWeek; // 记录每个课程班已安排的每周次数
    private List<String> remainingCourseClassIds;

    // 状态评估缓存
    private double currentScore;
    private int teacherCrossCampusCount;
    private double classroomContinuityRate;


    /**
     * 构建初始状态的构造函数
     */
    public MctsState(SchedulingData data, SchedulingConstraints constraints, DataAccessor dataAccessor) {
        this.schedulingData = Objects.requireNonNull(data, "SchedulingData不能为null");
        this.constraints = Objects.requireNonNull(constraints, "SchedulingConstraints不能为null");
        this.dataAccessor = Objects.requireNonNull(dataAccessor, "DataAccessor不能为null");

        if (data.hasCriticalErrors()) {
            logger.error("基础数据存在严重错误，无法构建初始状态");
            throw new IllegalArgumentException("基础数据校验失败: " + data.getValidationErrors());
        }

        loadOriginalResourceData();
        initSchedulingProgress();
        validateInitialState();
        resetScoreCache();

        logger.info("初始状态构建完成，待排课程数量: {}", getRemainingCourseCount());
    }

    public MctsState(MctsState other) {
        // 复制基础参数
        this.maxIterations = other.maxIterations;
        this.timeoutMillis = other.timeoutMillis;
        this.earlyStopThreshold = other.earlyStopThreshold;
        this.scoreImprovementThreshold = other.scoreImprovementThreshold;
        this.teacherConstraintWeight = other.teacherConstraintWeight;
        this.classroomUtilizationWeight = other.classroomUtilizationWeight;
        this.baseScore = other.baseScore;
        this.maxTeacherScore = other.maxTeacherScore;
        this.maxClassroomScore = other.maxClassroomScore;

        // 复制引用类型（深拷贝）
        this.schedulingData = other.schedulingData; // 假设SchedulingData是不可变的
        this.constraints = other.constraints;       // 假设约束是不可变的
        this.dataAccessor = other.dataAccessor;

        // 深拷贝集合类型
        this.originalStudentTimeSlotsMap = copyMapOfSets(other.originalStudentTimeSlotsMap);
        this.originalTeacherOccupancy = copyMapOfSets(other.originalTeacherOccupancy);
        this.originalClassroomOccupancy = copyMapOfSets(other.originalClassroomOccupancy);
        this.allAvailableTimeSlots = new HashSet<>(other.allAvailableTimeSlots);

        // 深拷贝排课进度数据（核心）
        this.scheduledSessions = new HashMap<>();
        for (Map.Entry<String, List<List<TimeSlot>>> entry : other.scheduledSessions.entrySet()) {
            List<List<TimeSlot>> copiedSessions = entry.getValue().stream()
                    .map(session -> new ArrayList<>(session))
                    .collect(Collectors.toList());
            this.scheduledSessions.put(entry.getKey(), copiedSessions);
        }

        this.scheduledCountPerWeek = new HashMap<>(other.scheduledCountPerWeek);
        this.remainingCourseClassIds = new ArrayList<>(other.remainingCourseClassIds);

        // 重置评分缓存
        resetScoreCache();
    }

    /**
     * 工具方法：深拷贝Map<String, Set<TimeSlot>>
     */
    private Map<String, Set<TimeSlot>> copyMapOfSets(Map<String, Set<TimeSlot>> source) {
        Map<String, Set<TimeSlot>> copy = new HashMap<>();
        for (Map.Entry<String, Set<TimeSlot>> entry : source.entrySet()) {
            copy.put(entry.getKey(), new HashSet<>(entry.getValue()));
        }
        return copy;
    }


    // ------------------------------ 参数配置方法 ------------------------------

    public void setTerminationParameters(int maxIterations, long timeoutMillis,
                                         int earlyStopThreshold, double scoreImprovementThreshold) {
        // 参数合法性验证
        if (maxIterations <= 0) {
            logger.warn("最大迭代次数必须为正数，使用默认值: {}", this.maxIterations);
        } else {
            this.maxIterations = maxIterations;
        }

        if (timeoutMillis <= 0) {
            logger.warn("超时时间必须为正数，使用默认值: {}", this.timeoutMillis);
        } else {
            this.timeoutMillis = timeoutMillis;
        }

        if (earlyStopThreshold <= 0) {
            logger.warn("早停阈值必须为正数，使用默认值: {}", this.earlyStopThreshold);
        } else {
            this.earlyStopThreshold = earlyStopThreshold;
        }

        if (scoreImprovementThreshold <= 0 || scoreImprovementThreshold >= 1) {
            logger.warn("分数改进阈值必须在(0,1)之间，使用默认值: {}", this.scoreImprovementThreshold);
        } else {
            this.scoreImprovementThreshold = scoreImprovementThreshold;
        }

        logger.debug("迭代参数已更新 - 最大次数: {}, 超时: {}ms, 早停阈值: {}, 分数改进阈值: {}",
                maxIterations, timeoutMillis, earlyStopThreshold, scoreImprovementThreshold);
    }

    public void setScoreWeights(double teacherWeight, double classroomWeight) {
        if (teacherWeight < 0 || classroomWeight < 0) {
            logger.warn("权重不能为负数，使用默认值 - 教师约束: {}, 教室利用率: {}",
                    teacherConstraintWeight, classroomUtilizationWeight);
            return;
        }

        if (teacherWeight + classroomWeight != 1.0) {
            logger.warn("权重总和不为1，将自动归一化");
            double total = teacherWeight + classroomWeight;
            teacherWeight /= total;
            classroomWeight /= total;
        }
        this.teacherConstraintWeight = teacherWeight;
        this.classroomUtilizationWeight = classroomWeight;
        logger.debug("评分权重已更新 - 教师约束: {}, 教室利用率: {}",
                teacherWeight, classroomWeight);
    }

    /**
     * 设置状态评估基础参数
     * @param baseScore 基础分数（0~100）
     * @param maxTeacherScore 教师约束最大得分
     * @param maxClassroomScore 教室利用率最大得分
     */
    public void setEvaluationBaseParameters(int baseScore, int maxTeacherScore, int maxClassroomScore) {
        // 基础分必须在合理范围内
        if (baseScore < 0 || baseScore > 100) {
            logger.warn("基础分数必须在0~100之间，使用默认值: {}", this.baseScore);
        } else {
            this.baseScore = baseScore;
        }

        // 分项最大分必须为正数且总和不超过40（确保总分不超过100）
        if (maxTeacherScore <= 0 || maxClassroomScore <= 0) {
            logger.warn("分项最大得分必须为正数，使用默认值 - 教师: {}, 教室: {}",
                    this.maxTeacherScore, this.maxClassroomScore);
        } else if (maxTeacherScore + maxClassroomScore > 40) {
            logger.warn("分项得分总和不能超过40，使用默认值 - 教师: {}, 教室: {}",
                    this.maxTeacherScore, this.maxClassroomScore);
        } else {
            this.maxTeacherScore = maxTeacherScore;
            this.maxClassroomScore = maxClassroomScore;
        }

        logger.debug("评估基础参数已更新 - 基础分: {}, 教师最大分: {}, 教室最大分: {}",
                baseScore, maxTeacherScore, maxClassroomScore);
    }


    // ------------------------------ 状态评估核心方法 ------------------------------

    /**
     * 计算当前状态评分（核心评分逻辑）
     */
    public double calculateStateScore() {
        if (hasHardConflicts()) {
            this.currentScore = 0;
            return 0;
        }

        int teacherScore = calculateTeacherConstraintScore();
        int classroomScore = calculateClassroomUtilizationScore();

        this.currentScore = baseScore +
                (teacherScore * teacherConstraintWeight) +
                (classroomScore * classroomUtilizationWeight);

        logger.debug("状态评分计算完成 - 总分: {:.2f}, 教师约束分: {}, 教室利用率分: {}",
                currentScore, teacherScore, classroomScore);
        return currentScore;
    }

    /**
     * 计算教师约束得分（避免跨校区连排）
     */
    private int calculateTeacherConstraintScore() {
        teacherCrossCampusCount = 0;
        Map<String, List<TimeSlot>> teacherTimeSlots = getTeacherScheduledTimeSlots();

        for (Map.Entry<String, List<TimeSlot>> entry : teacherTimeSlots.entrySet()) {
            String teacherId = entry.getKey();
            List<TimeSlot> sortedSlots = entry.getValue().stream()
                    .sorted(Comparator.comparing(TimeSlot::getStartTime))
                    .collect(Collectors.toList());

            // 检查连续时间槽是否跨校区
            for (int i = 0; i < sortedSlots.size() - 1; i++) {
                TimeSlot current = sortedSlots.get(i);
                TimeSlot next = sortedSlots.get(i + 1);

                if (areTimeSlotsConsecutive(current, next)) {
                    Integer currentCampus = getCourseCampusByCourseClassId(current.getCourseClassId());
                    Integer nextCampus = getCourseCampusByCourseClassId(next.getCourseClassId());

                    if (currentCampus != null && nextCampus != null && !currentCampus.equals(nextCampus)) {
                        teacherCrossCampusCount++;
                        logger.debug("教师[{}]存在跨校区连续上课: 课程[{}]在校区[{}]与课程[{}]在校区[{}]",
                                teacherId, current.getCourseClassId(), currentCampus,
                                next.getCourseClassId(), nextCampus);
                    }
                }
            }
        }

        int score = 10 - (teacherCrossCampusCount * 2);
        return Math.max(0, Math.min(score, maxTeacherScore));
    }

    /**
     * 根据课程班ID获取校区信息
     */
    private Integer getCourseCampusByCourseClassId(String courseClassId) {
        if (courseClassId == null || courseClassId.isEmpty()) {
            logger.warn("课程班ID为空，无法获取校区信息");
            return null;
        }

        CourseClassInfo courseClass = schedulingData.getCourseClasses().get(courseClassId);
        if (courseClass == null) {
            logger.warn("未找到课程班[{}]的信息，无法获取校区", courseClassId);
            return null;
        }

        return courseClass.getCampus();
    }

    /**
     * 计算教室利用率得分
     */
    private int calculateClassroomUtilizationScore() {
        int totalScheduled = scheduledSessions.values().stream()
                .flatMap(List::stream)
                .mapToInt(List::size)
                .sum();
        if (totalScheduled == 0) {
            this.classroomContinuityRate = 0;
            return 0;
        }

        int continuityCount = 0;
        Map<String, List<TimeSlot>> classroomTimeSlots = getClassroomScheduledTimeSlots();

        for (List<TimeSlot> slots : classroomTimeSlots.values()) {
            List<TimeSlot> sortedSlots = slots.stream()
                    .sorted(Comparator.comparing(TimeSlot::getStartTime))
                    .collect(Collectors.toList());

            for (int i = 0; i < sortedSlots.size() - 1; i++) {
                if (areTimeSlotsConsecutive(sortedSlots.get(i), sortedSlots.get(i + 1))) {
                    continuityCount++;
                }
            }
        }

        this.classroomContinuityRate = (double) continuityCount / totalScheduled;
        int score = (int) Math.min(classroomContinuityRate / 0.8 * maxClassroomScore, maxClassroomScore);
        return Math.max(0, score);
    }

    /**
     * 检查是否存在硬冲突
     */
    public boolean hasHardConflicts() {
        if (checkResourceConflicts(getTeacherScheduledTimeSlots())) {
            return true;
        }
        if (checkResourceConflicts(getClassroomScheduledTimeSlots())) {
            return true;
        }
        return checkStudentConflicts();
    }


    // ------------------------------ 连续课时分配核心方法 ------------------------------

    /**
     * 为课程班分配一个连续课时组合（核心修改点）
     * 满足"每次课课时数"和"每周上课次数"的约束
     */
    public boolean assignContinuousSession(String courseClassId, List<TimeSlot> continuousGroup) {
        // 1. 验证课程班存在性
        CourseClassInfo courseClass = schedulingData.getCourseClasses().get(courseClassId);
        if (courseClass == null) {
            logger.warn("课程班[{}]不存在，分配失败", courseClassId);
            return false;
        }

        // 2. 检查连续课时组合的有效性
        if (continuousGroup == null || continuousGroup.isEmpty()) {
            logger.warn("连续课时组合不能为空，课程班[{}]分配失败", courseClassId);
            return false;
        }

        // 验证课时数是否匹配（如每次2节课）
        if (continuousGroup.size() != courseClass.getWeekType()) {
            logger.warn("课程班[{}]课时数不匹配，要求[{}]节，实际[{}]节",
                    courseClassId, courseClass.getWeekType(), continuousGroup.size());
            return false;
        }

        // 验证是否为连续课时
        if (!areTimeSlotsContinuous(continuousGroup)) {
            logger.warn("课程班[{}]的课时组合不是连续的，分配失败", courseClassId);
            return false;
        }

        // 3. 检查是否已达到每周最大上课次数
        int currentCount = scheduledCountPerWeek.getOrDefault(courseClassId, 0);
        if (currentCount >= courseClass.getLessonCount()) {
            logger.warn("课程班[{}]已达到每周最大上课次数[{}]",
                    courseClassId, courseClass.getLessonCount());
            return false;
        }

        // 4. 检查连续课时组合是否可用（所有时间槽均未被占用）
        if (!areAllTimeSlotsAvailable(continuousGroup)) {
            logger.warn("课程班[{}]的连续课时组合已被占用，分配失败", courseClassId);
            return false;
        }

        // 5. 检查教师和教室冲突（连续课时内均不可冲突）
        if (hasConflictInContinuousGroup(courseClassId, continuousGroup)) {
            logger.warn("课程班[{}]的连续课时组合存在冲突，分配失败", courseClassId);
            return false;
        }

        // 6. 执行分配
        scheduledSessions.computeIfAbsent(courseClassId, k -> new ArrayList<>()).add(continuousGroup);
        scheduledCountPerWeek.put(courseClassId, currentCount + 1);
        allAvailableTimeSlots.removeAll(continuousGroup);

        // 7. 标记时间槽所属课程班
        continuousGroup.forEach(slot -> slot.setCourseClassId(courseClassId));

        // 8. 如果已满足每周次数，从剩余列表移除
        if (scheduledCountPerWeek.get(courseClassId) >= courseClass.getLessonCount()) {
            remainingCourseClassIds.remove(courseClassId);
            logger.debug("课程班[{}]已满足每周[{}]次上课要求，从待排列表移除",
                    courseClassId, courseClass.getLessonCount());
        }

        resetScoreCache();
        logger.debug("课程班[{}]成功分配连续课时组合: {}", courseClassId, continuousGroup);
        return true;
    }

    /**
     * 检查一组时间槽是否为连续课时
     */
    private boolean areTimeSlotsContinuous(List<TimeSlot> slots) {
        if (slots.size() <= 1) {
            return true; // 单课时也算连续
        }

        // 按节次排序
        List<TimeSlot> sortedSlots = new ArrayList<>(slots);
        sortedSlots.sort(Comparator.comparingInt(TimeSlot::getStartSession));

        // 检查是否同一天且节次连续
        TimeSlot first = sortedSlots.get(0);
        for (int i = 1; i < sortedSlots.size(); i++) {
            TimeSlot current = sortedSlots.get(i);
            if (!first.getDayOfWeek().equals(current.getDayOfWeek()) ||
                    current.getStartSession() != sortedSlots.get(i-1).getEndSession() + 1) {
                return false;
            }
        }
        return true;
    }

    /**
     * 检查连续课时组合内是否有冲突
     */
    private boolean hasConflictInContinuousGroup(String courseClassId, List<TimeSlot> group) {
        // 获取课程相关资源
        CourseClassInfo courseClass = schedulingData.getCourseClasses().get(courseClassId);
        String teacherId = courseClass.getPreferredTeacherId();
        classroom room = dataAccessor.getClassroomByCourseClassId(courseClassId);
        String classroomId = room != null ? room.getId() : null;

        // 检查教师冲突
        if (teacherId != null) {
            for (TimeSlot slot : group) {
                if (isTeacherBusy(teacherId, slot)) {
                    return true;
                }
            }
        }

        // 检查教室冲突
        if (classroomId != null) {
            for (TimeSlot slot : group) {
                if (isClassroomBusy(classroomId, slot)) {
                    return true;
                }
            }
        }

        // 检查学生冲突
        List<String> studentIds = dataAccessor.getStudentsByCourseClassId(courseClassId);
        if (studentIds != null && !studentIds.isEmpty()) {
            for (String studentId : studentIds) {
                Set<TimeSlot> studentSlots = originalStudentTimeSlotsMap.getOrDefault(studentId, Collections.emptySet());
                for (TimeSlot slot : group) {
                    for (TimeSlot studentSlot : studentSlots) {
                        if (slot.overlaps(studentSlot)) {
                            return true;
                        }
                    }
                }
            }
        }

        return false;
    }

    /**
     * 检查所有时间槽是否可用
     */
    private boolean areAllTimeSlotsAvailable(List<TimeSlot> slots) {
        for (TimeSlot slot : slots) {
            if (!allAvailableTimeSlots.contains(slot)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 检查教师在指定时间是否忙碌
     */
    private boolean isTeacherBusy(String teacherId, TimeSlot slot) {
        // 检查原始占用
        Set<TimeSlot> originalSlots = originalTeacherOccupancy.getOrDefault(teacherId, Collections.emptySet());
        for (TimeSlot original : originalSlots) {
            if (slot.overlaps(original)) {
                return true;
            }
        }

        // 检查已排课程
        for (List<List<TimeSlot>> sessions : scheduledSessions.values()) {
            for (List<TimeSlot> session : sessions) {
                for (TimeSlot scheduled : session) {
                    // 获取该时间槽对应的教师ID
                    String scheduledTeacherId = getTeacherIdByCourseClassId(scheduled.getCourseClassId());
                    if (teacherId.equals(scheduledTeacherId) && slot.overlaps(scheduled)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 检查教室在指定时间是否忙碌
     */
    private boolean isClassroomBusy(String classroomId, TimeSlot slot) {
        // 检查原始占用
        Set<TimeSlot> originalSlots = originalClassroomOccupancy.getOrDefault(classroomId, Collections.emptySet());
        for (TimeSlot original : originalSlots) {
            if (slot.overlaps(original)) {
                return true;
            }
        }

        // 检查已排课程
        for (List<List<TimeSlot>> sessions : scheduledSessions.values()) {
            for (List<TimeSlot> session : sessions) {
                for (TimeSlot scheduled : session) {
                    // 获取该时间槽对应的教室ID
                    String scheduledClassroomId = getClassroomIdByCourseClassId(scheduled.getCourseClassId());
                    if (classroomId.equals(scheduledClassroomId) && slot.overlaps(scheduled)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }


    // ------------------------------ 辅助方法 ------------------------------

    public void resetScoreCache() {
        this.currentScore = 0;
        this.teacherCrossCampusCount = 0;
        this.classroomContinuityRate = 0;
    }

    /**
     * 获取教师已排时间槽映射
     */
    private Map<String, List<TimeSlot>> getTeacherScheduledTimeSlots() {
        Map<String, List<TimeSlot>> result = new HashMap<>();

        for (Map.Entry<String, List<List<TimeSlot>>> entry : scheduledSessions.entrySet()) {
            String courseClassId = entry.getKey();
            List<TimeSlot> allSlots = entry.getValue().stream()
                    .flatMap(List::stream)
                    .collect(Collectors.toList());

            CourseClassInfo courseClass = schedulingData.getCourseClasses().get(courseClassId);
            if (courseClass == null || courseClass.getPreferredTeacherId() == null) {
                logger.warn("课程班[{}]未分配教师，跳过教师时间槽统计", courseClassId);
                continue;
            }
            String teacherId = courseClass.getPreferredTeacherId();

            result.computeIfAbsent(teacherId, k -> new ArrayList<>()).addAll(allSlots);
        }
        return result;
    }

    /**
     * 获取教室已排时间槽映射
     */
    private Map<String, List<TimeSlot>> getClassroomScheduledTimeSlots() {
        Map<String, List<TimeSlot>> result = new HashMap<>();

        for (Map.Entry<String, List<List<TimeSlot>>> entry : scheduledSessions.entrySet()) {
            String courseClassId = entry.getKey();
            List<TimeSlot> allSlots = entry.getValue().stream()
                    .flatMap(List::stream)
                    .collect(Collectors.toList());

            classroom room = dataAccessor.getClassroomByCourseClassId(courseClassId);
            if (room == null) {
                logger.warn("课程班[{}]未分配教室，跳过教室时间槽统计", courseClassId);
                continue;
            }

            String classroomId = room.getId();
            if (classroomId == null || classroomId.trim().isEmpty()) {
                logger.warn("课程班[{}]的教室ID为空，跳过教室时间槽统计", courseClassId);
                continue;
            }

            result.computeIfAbsent(classroomId, k -> new ArrayList<>()).addAll(allSlots);
        }
        return result;
    }

    /**
     * 检查资源时间冲突
     */
    private boolean checkResourceConflicts(Map<String, List<TimeSlot>> resourceMap) {
        for (Map.Entry<String, List<TimeSlot>> entry : resourceMap.entrySet()) {
            String resourceId = entry.getKey();
            List<TimeSlot> slots = entry.getValue();

            for (int i = 0; i < slots.size(); i++) {
                for (int j = i + 1; j < slots.size(); j++) {
                    if (slots.get(i).overlaps(slots.get(j))) {
                        logger.warn("资源[{}]存在时间冲突: {} 与 {}",
                                resourceId, slots.get(i), slots.get(j));
                        return true;
                    }
                }
            }

            Set<TimeSlot> originalSlots = originalTeacherOccupancy.getOrDefault(resourceId, Collections.emptySet());
            for (TimeSlot slot : slots) {
                for (TimeSlot original : originalSlots) {
                    if (slot.overlaps(original)) {
                        logger.warn("教师[{}]排课与原始占用冲突: {} 与 {}",
                                resourceId, slot, original);
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 检查学生时间冲突
     */
    private boolean checkStudentConflicts() {
        for (Map.Entry<String, List<List<TimeSlot>>> entry : scheduledSessions.entrySet()) {
            String courseClassId = entry.getKey();
            List<TimeSlot> allSlots = entry.getValue().stream()
                    .flatMap(List::stream)
                    .collect(Collectors.toList());

            List<String> studentIds = dataAccessor.getStudentsByCourseClassId(courseClassId);
            if (studentIds == null || studentIds.isEmpty()) {
                logger.warn("课程班[{}]没有学生信息，无法检查学生时间冲突", courseClassId);
                continue;
            }

            for (String studentId : studentIds) {
                Set<TimeSlot> studentSlots = originalStudentTimeSlotsMap.getOrDefault(studentId, Collections.emptySet());

                for (TimeSlot scheduledSlot : allSlots) {
                    for (TimeSlot studentSlot : studentSlots) {
                        if (scheduledSlot.overlaps(studentSlot)) {
                            logger.warn("学生[{}]在课程[{}]的时间冲突: {} 与 {}",
                                    studentId, courseClassId, scheduledSlot, studentSlot);
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

    /**
     * 加载原始资源数据
     */
    private void loadOriginalResourceData() {
        this.originalStudentTimeSlotsMap = schedulingData.getStudentOccupancy();
        if (this.originalStudentTimeSlotsMap == null) {
            logger.error("学生时间槽数据为空，可能是DataPreprocessor未正确加载数据");
            throw new IllegalStateException("学生时间槽数据初始化失败");
        }

        this.originalTeacherOccupancy = schedulingData.getTeacherOccupancy();
        if (this.originalTeacherOccupancy == null) {
            logger.error("教师占用数据为空，可能是DataPreprocessor未正确加载数据");
            throw new IllegalStateException("教师占用数据初始化失败");
        }

        this.originalClassroomOccupancy = schedulingData.getClassroomOccupancy();
        if (this.originalClassroomOccupancy == null) {
            logger.error("教室占用数据为空，可能是DataPreprocessor未正确加载数据");
            throw new IllegalStateException("教室占用数据初始化失败");
        }

        this.allAvailableTimeSlots = schedulingData.getAllAvailableTimeSlots();
        if (this.allAvailableTimeSlots == null || this.allAvailableTimeSlots.isEmpty()) {
            logger.warn("可用时间槽数据为空或不存在，可能导致排课无可用时间");
        }

        logger.debug("原始资源数据加载完成：");
        logger.debug(" - 学生时间槽数量: {}", originalStudentTimeSlotsMap.size());
        logger.debug(" - 教师数量: {}", originalTeacherOccupancy.size());
        logger.debug(" - 教室数量: {}", originalClassroomOccupancy.size());
        logger.debug(" - 可用时间槽总数: {}", allAvailableTimeSlots.size());
    }

    /**
     * 初始化排课进度
     */
    private void initSchedulingProgress() {
        this.scheduledSessions = new HashMap<>();
        this.scheduledCountPerWeek = new HashMap<>();
        this.remainingCourseClassIds = new ArrayList<>(schedulingData.getCourseClasses().keySet());

        // 按优先级排序待排课程
        this.remainingCourseClassIds.sort((id1, id2) -> {
            int priority1 = schedulingData.getCourseClasses().get(id1).getPriority();
            int priority2 = schedulingData.getCourseClasses().get(id2).getPriority();
            return Integer.compare(priority1, priority2);
        });

        logger.debug("排课进度初始化完成 - 待排课程: {} 门", remainingCourseClassIds.size());
    }

    /**
     * 验证初始状态合法性
     */
    private void validateInitialState() {
        if (schedulingData.getCourseClasses().isEmpty()) {
            logger.warn("没有待排课程数据，排课过程将无法进行");
        }

        if (allAvailableTimeSlots.isEmpty()) {
            schedulingData.addValidationError("没有可用的时间槽，无法进行排课");
        }

        if (schedulingData.getTeachers().isEmpty()) {
            schedulingData.addValidationError("没有教师数据，无法进行排课");
        }

        if (originalClassroomOccupancy.isEmpty()) {
            schedulingData.addConflictWarning("没有教室数据，可能导致排课失败");
        }
    }

    /**
     * 根据课程班ID获取教师ID
     */
    private String getTeacherIdByCourseClassId(String courseClassId) {
        CourseClassInfo courseClass = schedulingData.getCourseClasses().get(courseClassId);
        return courseClass != null ? courseClass.getPreferredTeacherId() : null;
    }

    /**
     * 根据课程班ID获取教室ID
     */
    private String getClassroomIdByCourseClassId(String courseClassId) {
        classroom room = dataAccessor.getClassroomByCourseClassId(courseClassId);
        return room != null ? room.getId() : null;
    }

    /**
     * 检查两个时间槽是否连续
     */
    public boolean areTimeSlotsConsecutive(TimeSlot slot1, TimeSlot slot2) {
        if (slot1 == null || slot2 == null) {
            return false;
        }

        if (!slot1.getDayOfWeek().equals(slot2.getDayOfWeek())) {
            return false;
        }

        return slot1.getEndSession() + 1 == slot2.getStartSession();
    }

    // ------------------------------ Getter/Setter方法 ------------------------------

    // 补充参数getter方法，方便控制器获取当前配置
    public double getTeacherConstraintWeight() {
        return teacherConstraintWeight;
    }

    public double getClassroomUtilizationWeight() {
        return classroomUtilizationWeight;
    }

    public int getBaseScore() {
        return baseScore;
    }

    public int getMaxTeacherScore() {
        return maxTeacherScore;
    }

    public int getMaxClassroomScore() {
        return maxClassroomScore;
    }

    // 原有getter方法
    public int getRemainingCourseCount() {
        return remainingCourseClassIds.size();
    }

    public int getMaxIterations() {
        return maxIterations;
    }

    public long getTimeoutMillis() {
        return timeoutMillis;
    }

    public int getEarlyStopThreshold() {
        return earlyStopThreshold;
    }

    public double getScoreImprovementThreshold() {
        return scoreImprovementThreshold;
    }

    public double getCurrentScore() {
        return currentScore;
    }

    // 原始资源数据getter
    public Map<String, Set<TimeSlot>> getOriginalStudentTimeSlotsMap() {
        return originalStudentTimeSlotsMap;
    }

    public Map<String, Set<TimeSlot>> getOriginalTeacherOccupancy() {
        return originalTeacherOccupancy;
    }

    public Map<String, Set<TimeSlot>> getOriginalClassroomOccupancy() {
        return originalClassroomOccupancy;
    }

    public Set<TimeSlot> getAllAvailableTimeSlots() {
        return allAvailableTimeSlots;
    }

    public List<String> getRemainingCourseClassIds() {
        return new ArrayList<>(remainingCourseClassIds);
    }

    // 新增的排课数据getter
    public Map<String, List<List<TimeSlot>>> getScheduledSessions() {
        return new HashMap<>(scheduledSessions);
    }

    public Map<String, Integer> getScheduledCountPerWeek() {
        return new HashMap<>(scheduledCountPerWeek);
    }
}
